# -*- coding: utf-8 -*-
"""
Created on Tue Sep 29 16:32:21 2020

@author: DELL
"""
from tensorflow import keras 
import numpy as np

def Create_word_ids(datapath,sen_max_len,n):  #n是要控制循环的次数，来生成训练数据train_data和语言模型的标签target
    '''
    Parameters
    ----------
    datapath : str
        存储数据的路径.
    sen_max_len : int
        训练数据的长度.
    vocab_size: int
        词典大小
    n: int
        复制多少次训练数据

    Returns
    -------
    词典,训练数据,训练数据对应的标签target.
    '''

    f=open(datapath,'r',encoding='utf-8')
    lines=f.readlines()
    lines=[line.strip() for line in lines]#去除每行的换行符
    t = keras.preprocessing.text.Tokenizer()
    t.fit_on_texts(lines)
    word_index=t.word_index#生成字典
    l=len(word_index)
    #向字典里面添加特殊字符，这里只添加了一个特殊字符，因为我在数据集里面已经添加了句子的开始和结束特殊字符
    word_index['<unk>']=l+1
    
    
    whole_sens=' '.join(lines)
    whole_sens=whole_sens.split(' ')
    len_whole_sens=len(whole_sens)
    #构造训练数据和标签
    train_data=[]
    target=[]
    
    for i in range(len_whole_sens-sen_max_len):
        train_data.append(' '.join(whole_sens[i:i+sen_max_len]))
        target.append(' '.join(whole_sens[i+1:sen_max_len+i+1]))#将数据后移一位，构造标签，这个模型使用一个文本，然后预测下一个单词
        #比如 对于 ‘我今天吃了一个苹果’  可以使用‘我今天’作为一个训练数据，预测‘今天吃’。使用‘今天吃’预测‘天吃了’ 等等，上面这个循环就实现了这个
        
    #下面将训练数据复制n次
    train_data=train_data*n
    target=target*n
    
    #下面将句子都转化为对应id的形式
    train_data=t.texts_to_sequences(train_data)
    target=t.texts_to_sequences(target)
    train_data=keras.preprocessing.sequence.pad_sequences(train_data,maxlen=sen_max_len,padding='post')
    target=keras.preprocessing.sequence.pad_sequences(target,maxlen=sen_max_len,padding='post')
    return word_index,train_data,target


#上面已经完成将word转化为id的程序，接下面将单词转化为字符的utf-8编码的id
def Create_char_id_embedding(word_index,max_word_length):
    '''
    
    Parameters
    ----------
    word_index : dict
        词典，是单词和id 的对应关系.
    max_word_length : int
        因为单词的长度不一致，因而我们希望传入一个整数，来控制单词的长度.
    Returns
    -------
    一个二维矩阵，类似嵌入矩阵，可以将单词转化为对应的utf-8编码.
    
    '''
    
    bow=256 #单词的起始id  begin of word
    eow=257 #单词的结束id  end of word
    padding=258 #将单词转化为utf-8（0-255）编码的时候，不能使用0填充，因为0也是字符的ascii码

    bos=259 #句子的开始id  begin of sentence
    eos=260 #句子的结束id  end of sentence
    
    dict_len=len(word_index)+1#字典里面单词的个数
    word_embedding=np.ones([dict_len,max_word_length])*padding#都先初始化为填充的值
    #下面开始根据字典构造char_embedding矩阵
    for word,id in word_index.items():
        l=len(word)
        word=word.encode('utf-8','ignore')
        word_embedding[id][0]=bow
        for i in range(1,l+1):
            word_embedding[id][i]=word[i-1]
        word_embedding[id][l+1]=eow
        
    return word_embedding
       
def Create_char_Vector(dim):
    '''
    随机生成一个每个字符的vector  比如 a--->[22,55,....],根据上面那个方法，这里其实是
    a对应的ascii码97转化为[22,55,....],输入一个batch的句子，最终生成的数据是[batch_size,time_steps,max_word_len,max_char_vector_len]
    ,然后对这个四维数据进行卷积操作之后调整为LSTM需要数据维度大小[batch_size,time_steps,dim]
    

    Parameters
    ----------
    dim : int
        生成字符嵌入的维度.

    Returns
    -------
    一个大小为259*dim的矩阵.
    259是因为utf-8编码有256位字符因为是8位2进制，再加上bow,eow和padding，所以总共259个
    这是我根据我自己理解弄的，可能和别的代码不太一样

    '''
    return np.random.normal(0,1,size=[259,dim])